package scrum.client.project;

import ilarkesto.core.base.Utl;
import ilarkesto.core.scope.Scope;
import ilarkesto.gwt.client.Gwt;
import ilarkesto.gwt.client.HyperlinkWidget;
import ilarkesto.gwt.client.editor.AFieldModel;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Map;

import scrum.client.ScrumGwt;
import scrum.client.admin.Auth;
import scrum.client.collaboration.ForumSupport;
import scrum.client.common.LabelSupport;
import scrum.client.common.ReferenceSupport;
import scrum.client.common.ShowEntityAction;
import scrum.client.sprint.Sprint;
import scrum.client.sprint.Task;

import com.google.gwt.user.client.ui.Widget;

public class Scenario extends GScenario implements ReferenceSupport, LabelSupport, ForumSupport, Comparable<Scenario> {

	public static final String REFERENCE_PREFIX = "sce";
	private transient AFieldModel<String> taskStatusLabelModel;
	private transient AFieldModel<String> referencesLabelModel;
	private int percentLabel;
	public static String[] CRITICISM_VALUES = new String[] { "Minor", "Major", "Blocker" };
	public static String[] PROJECT_STATE_VALUES = new String[] { "Satisfied", "Unsatisfied", "In Progress" };
	public static int[] CRITICISM_INT_VALUES = new int[] { 1, 2, 3 };
	public static String[] PRIORITY_VALUES = new String[] { "1", "2", "3", "4", "5" };

	public Scenario(Map data) {
		super(data);
	}

	public AFieldModel<String> getReferencesLabelModel() {
		if (referencesLabelModel == null) referencesLabelModel = new AFieldModel<String>() {

			@Override
			public String getValue() {
				return getReferencesLabel();
			}
		};
		return referencesLabelModel;
	}

	public String getReferencesLabel() {
		String labelAdded = "";
		List<Quality> auxQualitys = new ArrayList<Quality>(this.getQualitys());
		if (this.getCriticism() != null) labelAdded += " " + getCriticism() + " | ";
		if (auxQualitys.size() > 0) {
			String labelQuality = "";
			if (auxQualitys.get(0).getLabel() != null) labelQuality = auxQualitys.get(0).getLabel();
			labelAdded += "Quality: " + auxQualitys.get(0).getReference() + ":" + labelQuality + " | ";
		}
		List<Requirement> auxRequirements = new ArrayList<Requirement>(this.getStoriesAssociates());
		if (auxRequirements.size() > 0) {
			labelAdded += "User stories: ";
			for (Requirement r : auxRequirements) {
				String labelRequirement = "";
				if (r.getLabel() != null) labelRequirement = ":" + r.getLabel();
				labelAdded += r.getReference() + labelRequirement + " | ";
			}
		}
		return labelAdded;
	}

	public AFieldModel<String> getTaskStatusLabelModel() {
		if (taskStatusLabelModel == null) taskStatusLabelModel = new AFieldModel<String>() {

			@Override
			public String getValue() {
				return getTaskStatusLabel();
			}
		};
		return taskStatusLabelModel;
	}

	public void setPercentLabel(int percentLabel) {
		this.percentLabel = percentLabel;
	}

	public int getPercentLabel() {
		List<Task> tasks = getTasksInSprint();
		int burned = Task.sumBurnedWork(tasks);
		int remaining = Task.sumRemainingWork(getTasksInSprint());
		if (remaining == 0) return 100;
		int burnedPercent = Gwt.percent(burned + remaining, burned);
		return burnedPercent;
	}

	public String getTaskStatusLabel() {
		List<Task> tasks = getTasksInSprint();
		int burned = Task.sumBurnedWork(tasks);
		int remaining = Task.sumRemainingWork(getTasksInSprint());
		if (remaining == 0)
			return tasks.isEmpty() ? "no tasks planned yet" : "100% completed, " + burned + " hrs burned";
		int burnedPercent = Gwt.percent(burned + remaining, burned);
		return burnedPercent + "% completed, " + remaining + " hrs left";
	}

	public List<Task> getTasksInSprint() {
		return getTasksInSprint(getProject().getCurrentSprint());
	}

	public List<Task> getTasksInSprint(Sprint sprint) {
		List<Task> result = new ArrayList<Task>();
		for (Requirement r : this.getStoriesAssociates()) {
			for (Task task : r.getTasks()) {
				if (!task.isClosedInPastSprintSet() && sprint.equals(task.getSprint())) result.add(task);
			}
		}
		return result;
	}

	public Scenario(Project project) {
		setProject(project);
	}

	@Override
	public String toHtml() {
		return ScrumGwt.toHtml(this, getLabel());
	}

	@Override
	public String getReference() {
		return REFERENCE_PREFIX + getNumber();
	}

	@Override
	public String toString() {
		return getReference() + " " + getLabel();
	}

	@Override
	public Widget createForumItemWidget() {
		return new HyperlinkWidget(new ShowEntityAction(ScenarioBacklogWidget.class, this, getLabel()));
	}

	@Override
	public int compareTo(Scenario o) {
		return Utl.compare(getLabel(), o.getLabel());
	}

	public static class Comparators {

		public static final Comparator<Scenario> LABEL_COMPARATOR = new Comparator<Scenario>() {

			@Override
			public int compare(Scenario a, Scenario b) {
				return Utl.compare(a.getLabel(), b.getLabel());
			}
		};

		public static Comparator<Scenario> CRITICISM = new Comparator<Scenario>() {

			@Override
			public int compare(Scenario o1, Scenario o2) {
				if (o1.getCriticism() == null) o1.setCriticismValue(0);
				if (o2.getCriticism() == null) o2.setCriticismValue(0);
				if (o1.getCriticismValue() > o2.getCriticismValue())
					return -1;
				else if (o1.getCriticismValue() == o2.getCriticismValue()) {
					return Utl.compare(o1.getLabel(), o2.getLabel());
				} else return 1;
			}
		};
	}

	@Override
	public boolean isEditable() {
		if (!getProject().isProductOwner(Scope.get().getComponent(Auth.class).getUser())) return false;
		return true;
	}

	public static final Comparator<Scenario> LABEL_COMPARATOR = new Comparator<Scenario>() {

		@Override
		public int compare(Scenario o1, Scenario o2) {
			if (o1.getCriticism() == null) o1.setCriticismValue(0);
			if (o2.getCriticism() == null) o2.setCriticismValue(0);
			if (o1.getCriticismValue() > o2.getCriticismValue())
				return -1;
			else if (o1.getCriticismValue() == o2.getCriticismValue())
				return Utl.compare(o1.getLabel(), o2.getLabel());
			else return 1;
		}
	};
}